﻿namespace Monadic
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;

    public static class Monadic
    {
        public static bool Any<TSource>(this TSource source)
        {
            return source != null;
        }

        public static bool Any<TSource>(this TSource source, Func<TSource, bool> predicate)
        {
            return predicate(source);
        }

        public static IEnumerable<TSource> Concat<TSource>(this TSource first, TSource second)
        {
            yield return first;
            yield return second;
        }

        public static TSource OrderBy<TSource, TKey>(this TSource source, Func<TSource, TKey> keySelector)
        {
            return source;
        }

        public static TSource OrderBy<TSource, TKey>(this TSource source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            return source;
        }

        public static TSource OrderByDescending<TSource, TKey>(this TSource source, Func<TSource, TKey> keySelector)
        {
            return source;
        }

        public static TSource OrderByDescending<TSource, TKey>(this TSource source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            return source;
        }

        public static IEnumerable<TSource> Repeat<TSource>(this TSource source)
        {
            while (true)
            {
                yield return source;
            }
        }
        
        public static TResult Select<TSource, TResult>(this TSource source, Func<TSource, TResult> selector)
        {
            return selector(source);
        }

        public static TResult SelectMany<TSource, TCollection, TResult>(this TSource source, Func<TSource, TCollection> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
        {
            return resultSelector(source, collectionSelector(source));
        }

        public static IEnumerable<TSource> ToEnumerable<TSource>(this TSource source)
        {
            return new[] { source };
        }

        public static Func<TSource> ToFunc<TSource>(this TSource source)
        {
            return () => source;
        }

        public static dynamic Where<TSource>(this TSource source, Func<TSource, bool> predicate)
        {
            if (predicate(source))
            {
                return source;
            }

            return null;
        }

    }
}
